home *** CD-ROM | disk | FTP | other *** search
/ Risc World 3 / Risc World 3.iso / SOFTWARE / ISSUE2 / PD / VINCE / !ViNCe / c / vncviewer < prev   
Text File  |  2002-07-10  |  32KB  |  1,103 lines

  1. /*
  2.  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
  3.  *
  4.  *  This is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This software is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this software; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  17.  *  USA.
  18.  */
  19.  
  20. /*
  21.  * vncviewer.c
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <time.h>
  26. #include <string.h>
  27.  
  28. #include "oslib/os.h"
  29. #include "oslib/osbyte.h"
  30. #include "oslib/wimp.h"
  31. #include "oslib/osspriteop.h"
  32. #include "oslib/colourtrans.h"
  33.  
  34. #include "vncviewer.h"
  35. #include "vnckeys.h"
  36. #include "display.h"
  37. #include "antitwit.h"
  38.  
  39. #define CFGFILE_LEN 1023
  40. #define SH (1<<16)
  41.  
  42.  
  43. DISPLAY display;
  44.  
  45. // choices
  46. int savewhenquit = 0;
  47. int fullscreen = 0;
  48. int bgcolour = 0;
  49. int offsetx = 0, offsety = 0;
  50. int antitwit = 0;
  51. int keepontop = 0;
  52. int openontop = 0;
  53. int noborder = 0;
  54. char password[9];
  55. int guess = 0;
  56. int debug = 0;
  57. int supporttight = 0;
  58. int bpp = 16;
  59. int displaycursor = 0;
  60. int checkclientbitmap = 0;
  61. int dither8 = 0;
  62. int scale = 100;
  63. int addrectshift = 1;
  64. int fastcopy = 0;
  65.  
  66. #define CLOSEACTION_QUIT                0
  67. #define CLOSEACTION_ICONBAR             1
  68. #define CLOSEACTION_TOGGLESCALE         2
  69. int closeaction = CLOSEACTION_QUIT;
  70.  
  71. // iconbar
  72. wimp_i iconbarhandle;
  73. osspriteop_area *iconbarsprite = NULL;
  74.  
  75. unsigned short rgb332_rgb555_table[256];
  76. static wimp_w window;
  77. static int connected = 0;
  78.  
  79. static int CreateSprite(void);
  80. static int CreateWindow(void);
  81. static void SendMouse(int force);
  82. static void RedrawWindow(wimp_draw *draw, bool *more);
  83.  
  84. static unsigned short pressedkeys[32];
  85. static int pressedkeyscount = 0;
  86. static int releasekeystime = 0x7f000000;
  87. static void release_keys(void);
  88. static void send_keys(int key1, int key2);
  89. static void send_key(int key);
  90.  
  91. static void close_window(void);
  92. static void set_window_extent(void);
  93.  
  94. static int lastmousex, lastmousey, lastmousetime, lastmousebuttons, mouseinside;
  95. static int lastkey, lastkeytime;
  96. static int screensizex, screensizey, visiblex, visibley;
  97. static char transtable[256];
  98.  
  99. static int done = 0;
  100.  
  101. static unsigned int versmaj = 0, versmin;
  102.  
  103.  
  104. // Called with release = 1 to release the special keys at the end
  105. // (very useful if the connection is shared).
  106. void check_ctrl_alt(int release) {
  107.   static int altpressed = 0;
  108.   static int ctrlpressed = 0;
  109.   static int checktime = 0;
  110.   int alt = 0, ctrl = 0;
  111.  
  112.   if (!release) {
  113.     if (clock() < checktime)
  114.       return;
  115.     checktime = clock()+3;
  116.     xos_byte(osbyte_SCAN_KEYBOARD, 0x80 | 1, 0, &ctrl, NULL);
  117.     xos_byte(osbyte_SCAN_KEYBOARD, 0x80 | 2, 0, &alt, NULL);
  118.     ctrl = !!ctrl;
  119.     alt = !!alt;
  120.   }
  121.  
  122.   if (alt != altpressed) {
  123.     if (alt)
  124.       SendKeyEvent(VNCKEY_ALT, 1);
  125.     else
  126.       SendKeyEvent(VNCKEY_ALT, 0);
  127.     altpressed = alt;
  128.   }
  129.  
  130.   if (ctrl != ctrlpressed) {
  131.     if (ctrl)
  132.       SendKeyEvent(VNCKEY_CTRL, 1);
  133.     else
  134.       SendKeyEvent(VNCKEY_CTRL, 0);
  135.     ctrlpressed = ctrl;
  136.   }
  137. }
  138.  
  139.  
  140. osspriteop_area *create_scaled_down_version(int sizex, int sizey) {
  141. // create a scaled down version of the current screen
  142.   osspriteop_area *area;
  143.   int step, x, y, r, g, b, i;
  144.   unsigned short *rd, *wr, *tmp;
  145.  
  146.   area = malloc(2*(sizex+1)*sizey+256);
  147.   if (!area)   return NULL;
  148.  
  149.   area->size = 2*(sizex+1)*sizey+256;
  150.   area->sprite_count = 0;
  151.   area->first = area->used = 16;
  152.   if (xosspriteop_create_sprite(osspriteop_USER_AREA, area, "sprite",
  153.                                 0, sizex, sizey, (os_mode)0x281680b5)) {
  154.     free(area);
  155.     return NULL;
  156.   }
  157.  
  158.   tmp = malloc(2*sizex*display.sizey);
  159.   if (!tmp) {
  160.     free(area);
  161.     return NULL;
  162.   }
  163.   // first scale down horizontally
  164.   step = (1024*sizex)/display.sizex;
  165.   rd = display.data;
  166.   for (y = display.sizey; y > 0; y--) {
  167.     wr = tmp + sizex*(display.sizey-y);
  168.     x = r = g = b = 0;
  169.     for (i = display.sizex; i > 0; i--) {
  170.  
  171.       r += (*rd)       & 31;
  172.       g += ((*rd)>>5)  & 31;
  173.       b += ((*rd)>>10) & 31;
  174.       rd++;
  175.  
  176.       x += step;
  177.       if (x >= 1024) {
  178.         r = (r*step)/x;
  179.         g = (g*step)/x;
  180.         b = (b*step)/x;
  181.         if (r > 31)   r = 31;
  182.         if (g > 31)   g = 31;
  183.         if (b > 31)   b = 31;
  184.         *wr++ = r | (g<<5) | (b<<10);
  185.         x -= 1024;
  186.         r = g = b = 0;
  187.       }
  188.     }
  189.   }
  190.   // then scale down vertically
  191.   step = (1024*sizey)/display.sizey;
  192.   for (x = sizex; x > 0; x--) {
  193.     rd = tmp + (sizex-x);
  194.     wr = (unsigned short *)(((char *)area) + 60);
  195.     wr += sizex-x;
  196.     y = r = g = b = 0;
  197.     for (i = display.sizey; i > 0; i--) {
  198.  
  199.       r += (*rd)       & 31;
  200.       g += ((*rd)>>5)  & 31;
  201.       b += ((*rd)>>10) & 31;
  202.       rd += sizex;
  203.  
  204.       y += step;
  205.       if (y >= 1024) {
  206.         r = (r*step)/y;
  207.         g = (g*step)/y;
  208.         b = (b*step)/y;
  209.         if (r > 31)   r = 31;
  210.         if (g > 31)   g = 31;
  211.         if (b > 31)   b = 31;
  212.         *wr = r | (g<<5) | (b<<10);
  213.         wr += sizex;
  214.         y -= 1024;
  215.         r = g = b = 0;
  216.       }
  217.     }
  218.   }
  219.  
  220.   free(tmp);
  221.  
  222.   return area;
  223. }
  224.  
  225.  
  226.  
  227. void poll() {
  228.   wimp_block wimp;
  229.   wimp_event_no action;
  230.  
  231.   /* Some events are queued to avoid reentrancy problems. -- VL */
  232.   xwimp_poll(wimp_QUEUE_MOUSE|wimp_QUEUE_KEY, &wimp, NULL, &action);
  233.   switch (action) {
  234.   case wimp_OPEN_WINDOW_REQUEST:
  235.     xwimp_open_window(&wimp.open);
  236.     break;
  237.  
  238.   case wimp_CLOSE_WINDOW_REQUEST:
  239.     close_window();
  240.     break;
  241.  
  242.   case wimp_POINTER_ENTERING_WINDOW:
  243.     mouseinside = 1;
  244.     if (!displaycursor)   xosbyte(osbyte_SELECT_POINTER, 0, 0);
  245.     xwimp_set_caret_position(window, -1, -1000, -1000, 40, -1);
  246.     break;
  247.  
  248.   case wimp_POINTER_LEAVING_WINDOW:
  249.     mouseinside = 0;
  250.     if (!displaycursor)   xosbyte(osbyte_SELECT_POINTER, 1, 0);
  251.     break;
  252.  
  253.   case wimp_REDRAW_WINDOW_REQUEST:
  254.     {
  255.       bool more;
  256.       xwimp_redraw_window(&wimp.redraw, &more);
  257.       RedrawWindow(&wimp.redraw, &more);
  258.     }
  259.     break;
  260.   case wimp_USER_MESSAGE:
  261.   case wimp_USER_MESSAGE_RECORDED:
  262.   case wimp_USER_MESSAGE_ACKNOWLEDGE:
  263.     switch (wimp.message.action) {
  264.     case message_QUIT:
  265.       done = 1;
  266.       break;
  267.     }
  268.   }
  269. }
  270.  
  271.  
  272. int main(int argc, char **argv) {
  273.   unsigned int ip = 0;
  274.   int arg, displayn, i;
  275.   int wimpmsg[4];
  276.   char configfile[CFGFILE_LEN+1];
  277.  
  278.   { // Get ViNCe version
  279.     FILE *f;
  280.     f = fopen("<ViNCe$Dir>.Version", "r");
  281.     if (f != NULL) {
  282.       fscanf(f, "VERSION=%u.%u", &versmaj, &versmin);
  283.       fclose(f);
  284.     }
  285.   }
  286.  
  287.   // parse arguments
  288.   displayn = 1; // default display
  289.   strcpy(password, "mypass");
  290.   *configfile = '\0';
  291.  
  292.   for (arg = 1; arg < argc; arg++) {
  293.     if (strcmp(argv[arg], "-display") == 0) {
  294.       arg++;
  295.       displayn = atoi(argv[arg]);
  296.     } else if (strcmp(argv[arg], "-config") == 0) {
  297.       arg++;
  298.       strncpy(configfile, argv[arg], CFGFILE_LEN+1);
  299.       if (configfile[CFGFILE_LEN] != '\0') {
  300.         fprintf(stderr, "Config file name too long\n");
  301.         exit(1);
  302.       }
  303.     } else if (strcmp(argv[arg], "-password") == 0) {
  304.       arg++;
  305.       strncpy(password, argv[arg], 8);
  306.       password[8] = '\0';
  307.     } else if (strcmp(argv[arg], "-8bpp") == 0) {
  308.       bpp = 8;
  309.     } else if (strcmp(argv[arg], "-dither8") == 0) {
  310.       dither8 = 1;
  311.     } else if (strcmp(argv[arg], "-tight") == 0) {
  312.       supporttight = 1;
  313.     } else if (strcmp(argv[arg], "-save") == 0) {
  314.       savewhenquit = 1;
  315.     } else if (strcmp(argv[arg], "-checkclientbitmap") == 0) {
  316.       checkclientbitmap = 1;
  317.     } else if (strcmp(argv[arg], "-cursor") == 0) {
  318.       displaycursor = 1;
  319.     } else if (strcmp(argv[arg], "-debug") == 0) {
  320.       debug = 1;
  321.     } else if (strcmp(argv[arg], "-full") == 0) {
  322.       fullscreen = 1;
  323.       arg++;
  324.       if (sscanf(argv[arg], "%x", &bgcolour) != 1)
  325.         bgcolour = 0x00000000;
  326.       else
  327.         bgcolour <<= 8;
  328.     } else if (strcmp(argv[arg], "-guess") == 0) {
  329.       guess = 3;
  330.     } else if (strcmp(argv[arg], "-bottom") == 0) {
  331.       openontop = 0;
  332.     } else if (strcmp(argv[arg], "-top") == 0) {
  333.       openontop = 1;
  334.     } else if (strcmp(argv[arg], "-noborder") == 0) {
  335.       noborder = 1;
  336.     } else if (strcmp(argv[arg], "-ontop") == 0) {
  337.       keepontop = 1;
  338.     } else if (strcmp(argv[arg], "-anti") == 0) {
  339.       antitwit = 1;
  340.     } else if (strcmp(argv[arg], "-fastcopy") == 0) {
  341.       fastcopy = 1;
  342.     } else if (strcmp(argv[arg], "-scale") == 0) {
  343.       arg++;
  344.       scale = atoi(argv[arg]);
  345.     } else if (strcmp(argv[arg], "-closewindow") == 0) {
  346.       arg++;
  347.       closeaction = atoi(argv[arg]);
  348.     } else if (arg == argc-1) {
  349.       // the last argument must be ipaddress
  350.       unsigned int ip0, ip1, ip2, ip3;
  351.       if (sscanf(argv[argc-1], "%u.%u.%u.%u", &ip0, &ip1, &ip2, &ip3) == 4)
  352.         ip = (ip0<<0) | (ip1<<8) | (ip2<<16) | (ip3<<24);
  353.       else {
  354.         fprintf(stderr, "The last argument must be the IP address\n");
  355.         exit(1);
  356.       }
  357.     }
  358.   }
  359.  
  360.   if (*configfile) {
  361.     FILE *fh;
  362.     fh = fopen(configfile, "r");
  363.     if (fh) {
  364.       while (!feof(fh)) {
  365.         char temp[512], arg[256], val[256];
  366.  
  367.         fgets(temp, 255, fh);
  368.         temp[255] = '\0';
  369.         if (strchr(temp, '=')) {
  370.           char *t;
  371.           t = strchr(temp, '=');
  372.           *t++ = '\0';
  373.           sscanf(temp, "%s", arg);
  374.           sscanf(t, "%s", val);
  375.         } else
  376.           *arg = '\0';
  377.  
  378.         if (strcmp(arg, "display") == 0) {
  379.           displayn = atoi(val);
  380.         } else if (strcmp(arg, "password") == 0) {
  381.           strncpy(password, val, 8);
  382.           password[8] = '\0';
  383.         } else if (strcmp(arg, "8bpp") == 0) {
  384.           if (atoi(val) == 1)  bpp = 8;
  385.         } else if (strcmp(arg, "dither8") == 0) {
  386.           dither8 = !!atoi(val);
  387.         } else if (strcmp(arg, "tight") == 0) {
  388.           supporttight = !!atoi(val);
  389.         } else if (strcmp(arg, "save") == 0) {
  390.           savewhenquit = !!atoi(val);
  391.         } else if (strcmp(arg, "checkclientbitmap") == 0) {
  392.           checkclientbitmap = !!atoi(val);
  393.         } else if (strcmp(arg, "cursor") == 0) {
  394.           displaycursor = !!atoi(val);
  395.         } else if (strcmp(arg, "save") == 0) {
  396.           savewhenquit = !!atoi(val);
  397.         } else if (strcmp(arg, "full") == 0) {
  398.           fullscreen = 1;
  399.           if (sscanf(val, "%x", &bgcolour) != 1)
  400.             bgcolour = 0x00000000;
  401.           else
  402.             bgcolour <<= 8;
  403.         } else if (strcmp(arg, "guess") == 0) {
  404.           guess = atoi(val);
  405.         } else if (strcmp(arg, "noborder") == 0) {
  406.           noborder = !!atoi(val);
  407.         } else if (strcmp(arg, "ontop") == 0) {
  408.           keepontop = !!atoi(val);
  409.         } else if (strcmp(arg, "openontop") == 0) {
  410.           openontop = !!atoi(val);
  411.         } else if (strcmp(arg, "anti") == 0) {
  412.           antitwit = !!atoi(val);
  413.         } else if (strcmp(arg, "fastcopy") == 0) {
  414.           fastcopy = !!atoi(val);
  415.         } else if (strcmp(arg, "scale") == 0) {
  416.           scale = atoi(val);
  417.         } else if (strcmp(arg, "addrectshift") == 0) {
  418.           addrectshift = atoi(val);
  419.         } else if (strcmp(arg, "closewindow") == 0) {
  420.           closeaction = atoi(val);
  421.         } else if (strcmp(arg, "server") == 0) {
  422.           unsigned int ip0, ip1, ip2, ip3;
  423.           if (sscanf(val, "%u.%u.%u.%u", &ip0, &ip1, &ip2, &ip3) == 4)
  424.             ip = (ip0<<0) | (ip1<<8) | (ip2<<16) | (ip3<<24);
  425.         }
  426.       } // endwhile
  427.       fclose(fh);
  428.     } // endif
  429.   }
  430.  
  431.   if (ip == 0) {
  432.     fprintf(stderr, "The IP address isn't defined\n");
  433.     exit(1);
  434.   }
  435.  
  436.   // reset our display structure
  437.   display.displaycontext = NULL;
  438.  
  439.   // dependencies
  440.   if (scale < 25)   scale = 25;
  441.   if (scale > 200)  scale = 200;
  442.   if (bpp == 8)     supporttight = 0;
  443.   if (bpp != 16)    dither8 = 0;
  444.  
  445.   if (closeaction != CLOSEACTION_ICONBAR)
  446.     closeaction = CLOSEACTION_QUIT;
  447.  
  448.   // setup as a Wimp task
  449.   // select which messages to receive
  450.   wimpmsg[0] = message_MODE_CHANGE;
  451.   wimpmsg[1] = 0;
  452.  
  453.   // initialise the wimp
  454.   if (xwimp_initialise(310, "ViNCe", (wimp_message_list *) wimpmsg,
  455.       NULL, NULL))
  456.     exit(1);
  457.  
  458.   // RGB332 table - used when either -8bpp or -dither8 is set
  459.   for (i = 0; i < 256; i++) {
  460.     int r, g, b;
  461.     r = i & 7;
  462.     g = (i>>3) & 7;
  463.     b = (i>>6) & 7;
  464.     r = (r*1168)/256;
  465.     g = (g*1168)/256;
  466.     b = (b*2728)/256;
  467.     rgb332_rgb555_table[i] = r | (g<<5) | (b<<10);
  468.   }
  469.  
  470.   // Now enter the main loop, processing VNC messages.
  471.   done = 0;
  472.   lastmousex = lastmousey = lastmousetime = -1000;
  473.   mouseinside = 0;
  474.   lastkey = 0;
  475.   lastkeytime = 0;
  476.  
  477.   while (!done) {
  478.     wimp_block wimp;
  479.     wimp_event_no action;
  480.  
  481.     ((int *) &wimp.key)[7] = 1<<15; // Set bit 15 to detect DeepKeys' presence
  482.     xwimp_poll(0, &wimp, NULL, &action);
  483.  
  484.     switch (action) {
  485.       case wimp_NULL_REASON_CODE:
  486.  
  487.         if (connected) {
  488.           int clk;
  489.  
  490.           check_ctrl_alt(0);
  491.           clk = clock();
  492.           if (keepontop && (clk > keepontop)) {
  493.             wimp_window_state state;
  494.  
  495.             state.w = window;
  496.             xwimp_get_window_state(&state);
  497.             state.next = wimp_TOP;
  498.             xwimp_open_window((wimp_open *)&state);
  499.  
  500.             keepontop = clock() + 50;
  501.  
  502.             if (displaycursor)
  503.               xosbyte(osbyte_SELECT_POINTER, 1, 0);
  504.             else
  505.               xosbyte(osbyte_SELECT_POINTER, 0, 0);
  506.             xwimp_set_caret_position(window, -1, -1000, -1000, 40, -1);
  507.           }
  508.  
  509.           if (clk > releasekeystime)   release_keys();
  510.  
  511.           if ((clk > lastmousetime) && (mouseinside))   SendMouse(0);
  512.  
  513.           if (!HandleRFBServerMessage()) {
  514.             fprintf(stderr, "Failed to read server msg\n");
  515.             done = 3;
  516.           }
  517.           {
  518.             static int flushtime = 0;
  519.             if (clock() > flushtime) {
  520.               display_flush();
  521.               flushtime = clock() + 3;
  522.             }
  523.           }
  524.  
  525.         } else {
  526.           // make a TCP connection to the VNC server
  527.           Bool ok;
  528.           int attempts = guess;
  529.           int port = 5900 + displayn;
  530.  
  531.           do {
  532.             ok = ConnectToRFBServer(ip, port);
  533.             if (ok)
  534.               break;
  535.             port++;
  536.           } while (attempts-- > 0);
  537.  
  538.           if (!ok) {
  539.             done = 4;
  540.           } else {
  541.             // Initialise the VNC connection, including reading the password
  542.             if (!InitialiseRFBConnection()) {
  543.               done = 5;
  544.             } else {
  545.               // Tell the VNC server which pixel format and encodings we want to use
  546.               SetFormatAndEncodings();
  547.               // create sprite with the correct size
  548.               display.sizex = si.framebufferWidth;
  549.               display.sizey = si.framebufferHeight;
  550.               CreateSprite();
  551.               CreateWindow();
  552.               connected = 1;
  553.               SendFramebufferUpdateRequest(0,0,display.sizex,display.sizey,0);
  554.             }
  555.           }
  556.         }
  557.         break;
  558.  
  559.       case wimp_CLOSE_WINDOW_REQUEST:
  560.         close_window();
  561.         break;
  562.  
  563.       case wimp_POINTER_ENTERING_WINDOW:
  564.         mouseinside = 1;
  565.         SendMouse(1);
  566.         if (!displaycursor)   xosbyte(osbyte_SELECT_POINTER, 0, 0);
  567.         xwimp_set_caret_position(window, -1, -1000, -1000, 40, -1);
  568.         break;
  569.  
  570.       case wimp_POINTER_LEAVING_WINDOW:
  571.         mouseinside = 0;
  572.         if (!displaycursor)   xosbyte(osbyte_SELECT_POINTER, 1, 0);
  573.         break;
  574.  
  575.       case wimp_KEY_PRESSED:
  576.         if (mouseinside) {
  577.           wimp_key_no key;
  578.  
  579.           release_keys();
  580.           key = wimp.key.c;
  581.           if (key >= 384) {
  582.             if (key < 512) {
  583.               static int keymap[] = {
  584.                 0,             VNCKEY_F1,      VNCKEY_F2,      VNCKEY_F3,
  585.                 VNCKEY_F4,     VNCKEY_F5,      VNCKEY_F6,      VNCKEY_F7,
  586.                 VNCKEY_F8,     VNCKEY_F9,      VNCKEY_TAB,     VNCKEY_END,
  587.                 VNCKEY_LEFT,   VNCKEY_RIGHT,   VNCKEY_DOWN,    VNCKEY_UP,
  588.                 0,             VNCKEY_F1|SH,   VNCKEY_F2|SH,   VNCKEY_F3|SH,
  589.                 VNCKEY_F4|SH,  VNCKEY_F5|SH,   VNCKEY_F6|SH,   VNCKEY_F7|SH,
  590.                 VNCKEY_F8|SH,  VNCKEY_F9|SH,   VNCKEY_TAB|SH,  VNCKEY_END|SH,
  591.                 VNCKEY_LEFT|SH,VNCKEY_RIGHT|SH,VNCKEY_PAGEDOWN,VNCKEY_PAGEUP,
  592.                 0,             VNCKEY_F1,      VNCKEY_F2,      VNCKEY_F3,
  593.                 VNCKEY_F4,     VNCKEY_F5,      VNCKEY_F6,      VNCKEY_F7,
  594.                 VNCKEY_F8,     VNCKEY_F9,      VNCKEY_TAB,     VNCKEY_END,
  595.                 VNCKEY_LEFT,   VNCKEY_RIGHT,   VNCKEY_DOWN,    VNCKEY_UP,
  596.                 0,             VNCKEY_F1|SH,   VNCKEY_F2|SH,   VNCKEY_F3|SH,
  597.                 VNCKEY_F4|SH,  VNCKEY_F5|SH,   VNCKEY_F6|SH,   VNCKEY_F7|SH,
  598.                 VNCKEY_F8|SH,  VNCKEY_F9|SH,   VNCKEY_TAB|SH,  VNCKEY_END|SH,
  599.                 VNCKEY_LEFT|SH,VNCKEY_RIGHT|SH,VNCKEY_PAGEDOWN,VNCKEY_PAGEUP,
  600.                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  601.                 VNCKEY_F10,    VNCKEY_F11,    VNCKEY_F12,    VNCKEY_INSERT,
  602.                 0, 0,
  603.                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  604.                 VNCKEY_F10|SH, VNCKEY_F11|SH, VNCKEY_F12|SH, VNCKEY_INSERT|SH,
  605.                 0, 0,
  606.                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  607.                 VNCKEY_F10,    VNCKEY_F11,    VNCKEY_F12,    VNCKEY_INSERT,
  608.                 0, 0,
  609.                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  610.                 VNCKEY_F10|SH, VNCKEY_F11|SH, VNCKEY_F12|SH, VNCKEY_INSERT|SH,
  611.                 0, 0
  612.               };
  613.               int vnckey;
  614.               vnckey = keymap[key-384];
  615.               if (vnckey) {
  616.                 int extra;
  617.                 extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  618.                 switch ((extra & (1<<15)) == 0 && (key & ~0x31) == 0x18e ?
  619.                   extra >> 16 : 0) {
  620.                 case 33:
  621.                   if (extra & 3)
  622.                     send_keys(VNCKEY_SHIFT, VNCKEY_PAGEUP);
  623.                   else
  624.                     send_key(VNCKEY_PAGEUP);
  625.                   break;
  626.                 case 54:
  627.                   if (extra & 3)
  628.                     send_keys(VNCKEY_SHIFT, VNCKEY_PAGEDOWN);
  629.                   else
  630.                     send_key(VNCKEY_PAGEDOWN);
  631.                   break;
  632.                 case 89:
  633.                   if (extra & 3)
  634.                     send_keys(VNCKEY_SHIFT, VNCKEY_UP);
  635.                   else
  636.                     send_key(VNCKEY_UP);
  637.                   break;
  638.                 case 99:
  639.                   if (extra & 3)
  640.                     send_keys(VNCKEY_SHIFT, VNCKEY_DOWN);
  641.                   else
  642.                     send_key(VNCKEY_DOWN);
  643.                   break;
  644.                 default:
  645.                   if (vnckey & SH)
  646.                     send_keys(VNCKEY_SHIFT, vnckey & ~SH);
  647.                   else
  648.                     send_key(vnckey);
  649.                 }
  650.               }
  651.             }
  652.           } else {
  653.             switch (key) {
  654.             case wimp_KEY_ESCAPE:  { // Escape or Ctrl-[
  655.               int extra;
  656.               extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  657.               send_key((extra & (1<<15)) || (extra >> 16) == 0 ?
  658.                 VNCKEY_ESCAPE : '['); // If DeepKeys not present, Escape sent.
  659.               break;
  660.             }
  661.             case wimp_KEY_DELETE:  { // Delete or Ctrl-?
  662.               int extra;
  663.               extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  664.               send_key((extra & (1<<15)) || (extra >> 16) == 52 ?
  665.                 VNCKEY_DELETE : '?'); // If DeepKeys not present, Delete sent.
  666.               break;
  667.             }
  668.             case wimp_KEY_HOME:    { // Home or Ctrl-^
  669.               int extra;
  670.               extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  671.               send_key((extra & (1<<15)) || (extra >> 16) == 32 ?
  672.                 VNCKEY_HOME : '^'); // If DeepKeys not present, Home sent.
  673.               break;
  674.             }
  675.             case 0:                  send_key('@');
  676.                                      break;
  677.             default:
  678.               if (key >= ' ')
  679.                 send_key(key);
  680.               else if (key > 26)
  681.                 send_key(key+64);
  682.               else if (key > 0) {
  683.                 int shift;
  684.                 xos_byte(osbyte_SCAN_KEYBOARD, 0x80 | 0, 0, &shift, NULL);
  685.                 if (key == wimp_KEY_RETURN) { // Return or Enter or Ctrl-M
  686.                   int extra;
  687.                   extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  688.                   if ((extra & (1<<15)) || (extra >> 16) != 84) {
  689.                     // DeepKeys not present or it is not Ctrl-M
  690.                     send_key(VNCKEY_ENTER);
  691.                     break;
  692.                   }
  693.                 } // key == wimp_KEY_RETURN
  694.                 else if (key == wimp_KEY_BACKSPACE) { // Backspace or Ctrl-H
  695.                   int extra;
  696.                   extra = ((int *) &wimp.key)[7]; // written by DeepKeys module
  697.                   if ((extra & (1<<15)) || (extra >> 16) == 30) {
  698.                     // DeepKeys not present or it is Backspace
  699.                     send_key(VNCKEY_BACKSPACE);
  700.                     break;
  701.                   }
  702.                 } // key == wimp_KEY_BACKSPACE
  703.                 send_key(key + (shift ? 64 : 96));
  704.               } // key > 0
  705.               break;
  706.             }
  707.           }
  708.         }
  709.         break;
  710.  
  711.       case wimp_MOUSE_CLICK:
  712.         if (wimp.pointer.w == wimp_ICON_BAR) {
  713.           wimp_window_state state;
  714.  
  715.           state.w = window;
  716.           xwimp_get_window_state(&state);
  717.           state.next = wimp_TOP;
  718.           xwimp_open_window((wimp_open *)&state);
  719.           xwimp_delete_icon(wimp_ICON_BAR, iconbarhandle);
  720.         } else
  721.           SendMouse(1);
  722.         break;
  723.  
  724.       case wimp_OPEN_WINDOW_REQUEST:
  725.         xwimp_open_window(&wimp.open);
  726.         break;
  727.  
  728.       case wimp_REDRAW_WINDOW_REQUEST:
  729.         {
  730.           bool more;
  731.           xwimp_redraw_window(&wimp.redraw, &more);
  732.           RedrawWindow(&wimp.redraw, &more);
  733.         }
  734.         break;
  735.  
  736.       case wimp_USER_MESSAGE:
  737.       case wimp_USER_MESSAGE_RECORDED:
  738.       case wimp_USER_MESSAGE_ACKNOWLEDGE:
  739.         switch (wimp.message.action) {
  740.         case message_QUIT:
  741.           done = 1;
  742.           break;
  743.         case message_MODE_CHANGE:
  744.           xcolourtrans_select_table_for_sprite(display.displaycontext,
  745.                                        (osspriteop_id)"sprite",
  746.                                        (os_mode)-1, (os_palette *)-1,
  747.                                        (osspriteop_trans_tab *)transtable, 0);
  748.           break;
  749.         }
  750.     }
  751.   }
  752.  
  753.   if (connected)
  754.     check_ctrl_alt(1);
  755.  
  756.   if (savewhenquit)
  757.      xosspriteop_save_sprite_file(osspriteop_USER_AREA,
  758.                (osspriteop_area *)display.displaycontext,
  759.                     "<ViNCe$Dir>.screendump");
  760.  
  761.   xosbyte(osbyte_SELECT_POINTER, 1, 0);
  762.   CloseConnection();
  763.  
  764.   return 0;
  765. }
  766.  
  767.  
  768. int CreateSprite() {
  769.  
  770.   osspriteop_area *area;
  771.  
  772.   display.displaycontext = malloc(2*(display.sizex+1)*display.sizey+256);
  773.   if (!display.displaycontext)   return 1;
  774.  
  775.   area = display.displaycontext;
  776.   area->size = 2*(display.sizex+1)*display.sizey+256;
  777.   area->sprite_count = 0;
  778.   area->first = area->used = 16;
  779.   if (xosspriteop_create_sprite(osspriteop_USER_AREA, area, "sprite",
  780.                   0, display.sizex, display.sizey, (os_mode)0x281680b5))
  781.       return 1;
  782.  
  783.   display.shortsperline = (display.sizex+1) & ~1;
  784.   display.data = (unsigned short *)(((char *)area)+60);
  785.  
  786.   xcolourtrans_select_table_for_sprite(display.displaycontext,
  787.                               (osspriteop_id)"sprite",
  788.                               (os_mode)-1, (os_palette *)-1,
  789.                               (osspriteop_trans_tab *)transtable, 0);
  790.   return 0;
  791. }
  792.  
  793.  
  794. int CreateWindow() {
  795.  
  796.   wimp_window win;
  797.   int sx, sy;
  798.   static char titletext[24];
  799.  
  800.   xos_read_mode_variable((os_mode)-1, os_MODEVAR_XWIND_LIMIT, &sx, NULL);
  801.   xos_read_mode_variable((os_mode)-1, os_MODEVAR_YWIND_LIMIT, &sy, NULL);
  802.   screensizex = 2*(sx+1);
  803.   screensizey = 2*(sy+1);
  804.  
  805.   visiblex = display.sizex*2*scale/100;
  806.   visibley = display.sizey*2*scale/100;
  807.   offsetx = (screensizex - visiblex)/2;
  808.   offsety = (screensizey - visibley)/2;
  809.  
  810.   // create a window
  811.   if (fullscreen) {
  812.     win.visible.x0 = 0;
  813.     win.visible.y0 = 0;
  814.     win.visible.x1 = screensizex;
  815.     win.visible.y1 = screensizey;
  816.   } else {
  817.     win.visible.x0            = offsetx;
  818.     win.visible.y0            = offsety;
  819.     win.visible.x1            = win.visible.x0 + visiblex;
  820.     win.visible.y1            = win.visible.y0 + visibley;
  821.   }
  822.   win.next                  = wimp_BOTTOM;
  823.   if (noborder)
  824.     win.flags  = wimp_WINDOW_MOVEABLE   | wimp_WINDOW_NO_BOUNDS  | wimp_WINDOW_NEW_FORMAT;
  825.   else
  826.     win.flags  = wimp_WINDOW_VSCROLL    | wimp_WINDOW_HSCROLL     |
  827.                  wimp_WINDOW_SIZE_ICON  | wimp_WINDOW_TITLE_ICON  |
  828.                  wimp_WINDOW_BACK_ICON  | wimp_WINDOW_TOGGLE_ICON |
  829.                  wimp_WINDOW_MOVEABLE   | wimp_WINDOW_NO_BOUNDS   |
  830.                  wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_NEW_FORMAT;
  831.   win.title_fg              = 7;
  832.   win.title_bg              = 2;
  833.   win.work_fg               = 7;
  834.   win.work_bg               = 0xff;
  835.   win.scroll_outer          = 3;
  836.   win.scroll_inner          = 1;
  837.   win.highlight_bg          = 12;
  838.   if (fullscreen) {
  839.     win.extent.x0             = -offsetx;
  840.     win.extent.y0             = -offsety;
  841.     win.extent.x1             = visiblex + offsetx;
  842.     win.extent.y1             = visibley + offsety;
  843.   } else {
  844.     win.extent.x0             = 0;
  845.     win.extent.y0             = 0;
  846.     win.extent.x1             = visiblex;
  847.     win.extent.y1             = visibley;
  848.   }
  849.   win.title_flags           = wimp_ICON_TEXT      | wimp_ICON_HCENTRED |
  850.                               wimp_ICON_VCENTRED  | wimp_ICON_INDIRECTED;
  851.   win.work_flags            = wimp_BUTTON_CLICK<<12;
  852.   win.sprite_area           = (osspriteop_area *)1;
  853.   win.xmin = win.ymin = 100;
  854.   if (versmaj > 0)
  855.     sprintf(titletext, "ViNCe (version %u.%u)", versmaj, versmin);
  856.   else
  857.     sprintf(titletext, "ViNCe");
  858.   win.title_data.indirected_text.text = titletext;
  859.   win.title_data.indirected_text.validation = NULL;
  860.   win.title_data.indirected_text.size = strlen(titletext);
  861.   win.icon_count            = 0;
  862.   if (xwimp_create_window(&win, &window))  return 1;
  863.  
  864.   set_window_extent();
  865.  
  866.   return 0;
  867. }
  868.  
  869. void set_window_extent() {
  870.   wimp_window_state state;
  871.  
  872.   visiblex = display.sizex*2*scale/100;
  873.   visibley = display.sizey*2*scale/100;
  874.   offsetx = (screensizex - visiblex)/2;
  875.   offsety = (screensizey - visibley)/2;
  876.  
  877. // set extent
  878.  
  879.   state.w = window;
  880.   xwimp_get_window_state(&state);
  881.   if (keepontop || openontop)
  882.     state.next = wimp_TOP;
  883.   else
  884.     state.next = wimp_BOTTOM;
  885.   xwimp_open_window((wimp_open *)&state);
  886. }
  887.  
  888. void SendMouse(int force) {
  889.  
  890.   wimp_pointer ptr;
  891.   wimp_window_state state;
  892.   int x, y, but;
  893.  
  894.   state.w = window;
  895.   xwimp_get_window_state(&state);
  896.  
  897.   lastmousetime = clock() + 1;
  898.   xwimp_get_pointer_info(&ptr);
  899.  
  900.   x = 100*(ptr.pos.x - (state.visible.x0 - state.xscroll))/(2*scale);
  901.   y = display.sizey - 100*(ptr.pos.y - (state.visible.y1 - state.yscroll))/(2*scale);
  902.   but = 0;
  903.   if (ptr.buttons & 1)  but |= 4;
  904.   if (ptr.buttons & 2)  but |= 2;
  905.   if (ptr.buttons & 4)  but |= 1;
  906.   if (force || x != lastmousex || y != lastmousey || lastmousebuttons != but) {
  907.     SendPointerEvent(x, y, but);
  908.     lastmousex = x;
  909.     lastmousey = y;
  910.     lastmousebuttons = but;
  911.   }
  912. }
  913.  
  914.  
  915. void UpdateWindow(int x, int y, int w, int h) {
  916.  
  917.   int x1, y1;
  918.   wimp_draw draw;
  919.   bool more;
  920.  
  921.   x1 = 2*(x+w);
  922.   y1 = 2*(display.sizey-y);
  923.   x = 2*x;
  924.   y = 2*(display.sizey-(y+h));
  925.   x = x*scale/100;
  926.   y = y*scale/100;
  927.   x1 = x1*scale/100;
  928.   y1 = y1*scale/100;
  929.  
  930.   draw.w = window;
  931.   draw.box.x0 = x-2;
  932.   draw.box.y0 = y-2;
  933.   draw.box.x1 = x1+2;
  934.   draw.box.y1 = y1+2;
  935.   xwimp_update_window(&draw, &more);
  936.   RedrawWindow(&draw, &more);
  937. }
  938.  
  939.  
  940. void RedrawWindow(wimp_draw *draw, bool *more) {
  941.  
  942.   int x, y;
  943.   os_factors scaling;
  944.  
  945.   scaling.xmul = scaling.ymul = scale;
  946.   scaling.xdiv = scaling.ydiv = 100;
  947.  
  948.   x = draw->box.x0 - draw->xscroll;
  949.   y = draw->box.y1 - draw->yscroll;
  950.   while (*more) {
  951.     int antix0, antiy0, antix1, antiy1;
  952.  
  953.     antix0 = draw->clip.x0;
  954.     antiy0 = draw->clip.y0;
  955.     antix1 = draw->clip.x1;
  956.     antiy1 = draw->clip.y1;
  957.     xosspriteop_put_sprite_scaled(osspriteop_USER_AREA,
  958.                                   display.displaycontext,
  959.                                   (osspriteop_id)"sprite", x, y, 0, &scaling,
  960.                                   (osspriteop_trans_tab *)transtable);
  961.     if (fullscreen) {
  962.       xcolourtrans_set_gcol(bgcolour, 0, 0, NULL, NULL);
  963.       if (antix0 < x) {
  964.         xos_plot(os_MOVE_TO, 0, 0);
  965.         xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE, offsetx, screensizey);
  966.       }
  967.       if (antiy0 < x) {
  968.         xos_plot(os_MOVE_TO, offsetx, 0);
  969.         xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE, offsetx + visiblex, offsety);
  970.       }
  971.       if (antix1 > visiblex + x) {
  972.         xos_plot(os_MOVE_TO, offsetx + visiblex, 0);
  973.         xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE, screensizex, screensizey);
  974.       }
  975.       if (antiy1 > visibley + y) {
  976.         xos_plot(os_MOVE_TO, offsetx, offsety + visibley);
  977.         xos_plot(os_PLOT_TO | os_PLOT_RECTANGLE, offsetx + visiblex, screensizey);
  978.       }
  979.     }
  980.     xwimp_get_rectangle(draw, more);
  981.     if (antitwit)  antitwitter(antix0, antiy0, antix1-antix0, antiy1-antiy0);
  982.   }
  983. }
  984.  
  985.  
  986. void release_keys() {
  987.  
  988.   int i;
  989.  
  990.   for (i = 0; i < pressedkeyscount; i++) {
  991.     SendKeyEvent(pressedkeys[i], 0);
  992.   }
  993.   pressedkeyscount = 0;
  994.   releasekeystime = 0x7f000000;          // never
  995. }
  996.  
  997.  
  998. void send_keys(int key1, int key2) {
  999.  
  1000.   if (pressedkeyscount >= 30)   return;
  1001.   pressedkeys[pressedkeyscount+0] = key2;
  1002.   pressedkeys[pressedkeyscount+1] = key1;
  1003.   pressedkeyscount += 2;
  1004.   SendKeyEvent(key1, 1);
  1005.   SendKeyEvent(key2, 1);
  1006.   releasekeystime = clock()+4;
  1007. }
  1008.  
  1009.  
  1010. void send_key(int key) {
  1011.  
  1012.   if (pressedkeyscount >= 32)   return;
  1013.   pressedkeys[pressedkeyscount] = key;
  1014.   pressedkeyscount++;
  1015.   SendKeyEvent(key, 1);
  1016.   releasekeystime = clock()+4;
  1017. }
  1018.  
  1019.  
  1020.  
  1021. void close_window() {
  1022.  
  1023.   switch (closeaction) {
  1024.   case CLOSEACTION_QUIT:
  1025.     done = 2;
  1026.     break;
  1027.   case CLOSEACTION_ICONBAR:
  1028.     {
  1029.       int x, y;
  1030.  
  1031.       if (iconbarsprite)   free(iconbarsprite);
  1032.       y = 42;
  1033.       x = (1+(y*display.sizex)/display.sizey) & ~1;
  1034.       iconbarsprite = create_scaled_down_version(x, y);
  1035.       if (iconbarsprite) {
  1036.         wimp_icon_create icon;
  1037.  
  1038.         icon.w = (wimp_w) -1;
  1039.         icon.icon.extent.x0 = 0;
  1040.         icon.icon.extent.y0 = -4;
  1041.         icon.icon.extent.x1 = 2*x;
  1042.         icon.icon.extent.y1 = icon.icon.extent.y0 + 2*y;
  1043.         icon.icon.flags = 0x0000311a;
  1044.         icon.icon.data.indirected_sprite.id = (osspriteop_id)"sprite";
  1045.         icon.icon.data.indirected_sprite.area = (osspriteop_area *)iconbarsprite;
  1046.         icon.icon.data.indirected_sprite.size = strlen("sprite")+1;
  1047.         xwimp_create_icon(&icon, &iconbarhandle);
  1048.         xwimp_close_window(window);
  1049.       } else
  1050.         done = 2;
  1051.     }
  1052.     break;
  1053.   case CLOSEACTION_TOGGLESCALE:
  1054.     {
  1055.       static int firsttime = 1, toggled = 0, scale1, scale2;
  1056.  
  1057.       if (firsttime) {
  1058.         firsttime = 0;
  1059.         scale1 = scale;
  1060.         if (scale1 == 100)
  1061.           scale2 = 25;
  1062.         else
  1063.           scale2 = 100;
  1064.       }
  1065.       if (toggled)
  1066.         scale = scale1;
  1067.       else
  1068.         scale = scale2;
  1069.       toggled = !toggled;
  1070.  
  1071.       set_window_extent();
  1072.       UpdateWindow(0, 0, display.sizex, display.sizey);
  1073.     }
  1074.     break;
  1075.   }
  1076. }
  1077.  
  1078. int fast_copy_ok() {
  1079.   if (fastcopy && scale == 100) {
  1080.     wimp_window_state state;
  1081.     wimp_window_flags mask = wimp_WINDOW_NOT_COVERED|wimp_WINDOW_FULL_SIZE;
  1082.  
  1083.     state.w = window;
  1084.     xwimp_get_window_state(&state);
  1085.     return (state.flags & mask) == mask;
  1086.   }
  1087.   else
  1088.     return 0;
  1089. }
  1090.  
  1091. void BlockCopy(int rx, int ry, int rw, int rh, int sx, int sy) {
  1092.   int x0, y0, x1, y1, xd, yd;
  1093.  
  1094.   display_flush();
  1095.   x0 = 2*sx;
  1096.   x1 = 2*(sx+rw);
  1097.   y0 = 2*(display.sizey-(sy+rh));
  1098.   y1 = 2*(display.sizey-sy);
  1099.   xd = 2*rx;
  1100.   yd = 2*(display.sizey-(ry+rh));
  1101.   xwimp_block_copy(window, x0, y0, x1, y1, xd, yd);
  1102. }
  1103.